
#include "etl_dir.h"
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>

#ifndef WIN32
  #include <dirent.h>
  #include <fnmatch.h>
#else
  #include <io.h>
#endif

using namespace etl;

etl_dir::etl_dir( const char* glob )
{
    open_dir( glob );
}

etl_dir::etl_dir( const etl_dir& obj )
{
    copy( obj );
}

etl_dir::~etl_dir()
{
}

etl_dir& etl_dir::operator = ( const etl_dir& obj )
{
    return copy( obj );
}

int etl_dir::open_dir( const char* glob )
{
    if ( glob && (!is_reg( glob )) )
    {
        etl_string glob_spec = glob;

        if ( is_dir( glob_spec.c_str() ) )
        {
#ifndef WIN32
            return get_file_names( glob_spec.c_str(), NULL );
#else
            return get_file_names( glob_spec.c_str(), "*.*" );
#endif
        }
        else
        {
            int last_slash = glob_spec.rfind( PS );   

            etl_string path_part;
            if ( last_slash >= 0 )
                path_part = glob_spec.sub_string( 0, last_slash );

            etl_string glob_part;
            if ( ((int)glob_spec.length()) > (last_slash+1) )
            {
                glob_part = glob_spec.sub_string( last_slash + 1, glob_spec.length() - (last_slash + 1) );
            }

            return get_file_names( path_part.c_str(), glob_part.c_str() );
        }
    }

    return -1;
}

int etl_dir::clear()
{
    return names.clear();
}

int etl_dir::iter_begin()
{
    return names.iter_begin();
}

int etl_dir::iter_end()
{
    return names.iter_end();
}

int etl_dir::iter_next()
{
    return names.iter_next();
}

int etl_dir::iter_prev()
{
    return names.iter_prev();
}

etl_string* etl_dir::iter_data()
{
    return names.iter_data();
}

bool etl_dir::iter_valid()
{
    return names.iter_valid();
}

etl_dir& etl_dir::copy( const etl_dir& obj )
{
    names = obj.names;
    return *this;
}

bool etl_dir::is_dir( const char* path )
{
#ifndef WIN32
    struct stat path_info;
    if ( stat( path, &path_info ) == 0 )
        return(S_ISDIR(path_info.st_mode))?true:false;
#else
    struct _stat path_info;
    if ( _stat( path, &path_info ) == 0 )
        return(path_info.st_mode & _S_IFDIR)?true:false;
#endif
    return false;
}

bool etl_dir::is_reg( const char* path )
{
#ifndef WIN32
    struct stat path_info;
    if ( stat( path, &path_info ) == 0 )
        return(S_ISREG(path_info.st_mode))?true:false;
#else
    struct _stat path_info;
    if ( _stat( path, &path_info ) == 0 )
        return(path_info.st_mode & _S_IFREG)?true:false;
#endif
    return false;
}

int etl_dir::get_file_names( const char* path, const char* glob )
{
    names.clear();
    if ( path )
    {
#ifndef WIN32
        if ( DIR* d = opendir( path ) )
        {
            while ( struct dirent* d_entry = readdir(d) )
            {
                if ( (strncmp( ".", d_entry->d_name, 1 ) != 0) &&
                     (strncmp( "..", d_entry->d_name, 2 ) != 0) )
                {
                    etl_string file_name = d_entry->d_name;      
                    if ( glob )
                    {
                        if ( fnmatch( glob, d_entry->d_name, 0 ) == 0 )
                            names.append( file_name );
                    }
                    else names.append( file_name );
                }

            }
            closedir( d );
        }
#else
        etl_string full_spec;

        if ( glob )
            full_spec.format( "%s%s%s", path, PS, glob );
        else full_spec.format( "%s", path );

        struct _finddata_t fs;//files search structure    
        intptr_t handle; //Search handle

        if ( (handle = _findfirst(full_spec.c_str(),&fs))==-1 )
            return -1;
        do
        {
            if ( (strncmp( ".", fs.name, 1 ) != 0) &&
                 (strncmp( "..", fs.name, 2 ) != 0) )
            {
                etl_string name = fs.name;
                names.append( name );
            }
        } while ( (_findnext(handle,&fs))==0 );

        _findclose(handle);
#endif

        return 0;
    }
    return -1;
}
